<?php

abstract class Enum {

    private static $enumArray = array();

    private static $constCache = NULL;

    private $scalar;

    function __construct( $value ) {
        $ref = new ReflectionObject( $this );
        $consts = $ref->getConstants();
        if ( !in_array( $value, $consts, true ) ) {
            throw new InvalidArgumentException();
        }
        
        $this->scalar = $value;
    }

    final static function __callStatic( $label, $args ) {
        $class = get_called_class();
        $const = constant( "$class::$label" );
        return new $class( $const );
    }

    final function Val() {
        return $this->scalar;
    }

    final function __toString() {
        return (string)$this->scalar;
    }

    private static function getConstants() {
        if ( self::$constCache === NULL ) {
            $reflect = new ReflectionClass( get_called_class() );
            self::$constCache = $reflect->getConstants();
        }
        
        return self::$constCache;
    }

    public static function isValidValue( $value ) {
        $values = array_values( self::getConstants() );
        return in_array( $value, $values, $strict = true );
    }

    final public static function Values() {
        $className = get_called_class();
        if ( count( self::$enumArray ) == 0 ) {
            $class = new ReflectionClass( $className );
            $history = array();
            foreach ( $class->getConstants() as $val ) {
                $enum = new $className( $val );
                array_push( self::$enumArray, $enum );
            }
        }
        return self::$enumArray;
    }

}
